home *** CD-ROM | disk | FTP | other *** search
/ NeXTSTEP 3.3 (Developer)…68k, x86, SPARC, PA-RISC] / NeXTSTEP 3.3 Dev Intel.iso / NextDeveloper / Examples / DriverKit / SCSITape / SCSITape_reloc.tproj / SCSITape.m < prev    next >
Encoding:
Text File  |  1994-11-11  |  26.3 KB  |  1,200 lines

  1. /* 
  2.  * SCSITape.m -- implementation of scsi tape driver routines
  3.  *
  4.  * HISTORY
  5.  * 31-Mar-93    Phillip Dibner at NeXT
  6.  *    Created.
  7.  *
  8.  */ 
  9.  
  10.  
  11. #import <sys/errno.h>
  12. #import <sys/types.h>
  13. #import <sys/time.h>
  14. #import <sys/conf.h>
  15. #import <sys/uio.h>
  16. #import <sys/mtio.h>
  17. #import <bsd/dev/scsireg.h>
  18.  
  19. #import <driverkit/scsiTypes.h>
  20. #import <driverkit/align.h>
  21. #import <driverkit/kernelDriver.h>
  22. #import <driverkit/scsiTypes.h>
  23. #import <driverkit/return.h>
  24. #import <machkit/NXLock.h>
  25. #import <kernserv/prototypes.h>
  26. #import <kernserv/kern_server_types.h>
  27. #import "SCSITape.h"
  28. #import "SCSITapeTypes.h"
  29.  
  30. #define DRIVE_TYPE_LENGTH 80
  31.  
  32. #define USE_EBD    1        /* use "even byte disconnect" rather than 
  33.                  * "no disconnect during data xfer" for exabyte
  34.                  */
  35.  
  36. extern int st_devsw_init();
  37.  
  38. static int moveString();    /* rmv nulls & blanks from inquiry strings */
  39. void assign_cdb_c6s_len();    /* store length data in little-endian cdb_6s */
  40. void assign_msbd_numblocks();    /* store nblks in little-endian modesel bd */
  41. void assign_msbd_blocklength();    /* store blklen in little-endian modesel bd */
  42. int cdb_c6s_len_value();    /* byte swap to read length data in cdb */
  43. int er_info_value ();        /* byte swapping for sense reply info data */
  44.  
  45. id        stIdMap [NST];
  46.  
  47. @implementation SCSITape
  48.  
  49. + (IODeviceStyle)deviceStyle
  50. {
  51.     return IO_IndirectDevice;
  52. }
  53.  
  54. /*
  55.  * The protocol we need as an indirect device.
  56.  */
  57. static Protocol *protocols[] = {
  58.     @protocol(IOSCSIControllerExported),
  59.     nil
  60. };
  61.  
  62. + (Protocol **)requiredProtocols
  63. {
  64.     return protocols;
  65. }
  66.  
  67. static unsigned int tapeUnit = 0;
  68.  
  69. + (BOOL) probe: deviceDescription
  70. {
  71.     SCSITape            *tapeId = nil;
  72.     unsigned char        stTarget, stLun;
  73.     id                controllerId = 
  74.                     [deviceDescription directDevice];
  75.     stInitReturn_t        irtn = STR_ERROR;
  76.     BOOL            brtn = NO;
  77.     int                major;
  78.     
  79. /* asm volatile("int3");  */ // Early break to debugger
  80.     
  81.     if ((major = st_devsw_init()) < 0) {
  82.     return NO;
  83.     }
  84.  
  85.     for (stTarget=0; stTarget<SCSI_NTARGETS; stTarget++) {
  86.     for(stLun=0; stLun<SCSI_NLUNS; stLun++) {
  87.  
  88. #ifdef DEBUG
  89. IOLog ("SCSITape probe: target %d  lun %d\n", stTarget, stLun);
  90. #endif DEBUG
  91.  
  92.         if(tapeId == nil) {
  93.         /*
  94.          * Create an instance, do some basic 
  95.          * initialization. Set up a default 
  96.          * device name for error reporting during
  97.          * initialization.
  98.          */
  99.         tapeId = [SCSITape alloc];
  100.         }
  101.  
  102.         if ([controllerId reserveTarget:stTarget
  103.         lun:stLun
  104.         forOwner:tapeId]) {
  105.         /*
  106.          * Someone already has this one.
  107.          */
  108.         continue;   
  109.         }
  110.         else {
  111.         [tapeId setReservedTargetLun: YES];
  112.         }
  113.  
  114. #ifdef DEBUG
  115. IOLog ("SCSITape probe: about to init\n");
  116. #endif DEBUG
  117.  
  118.         irtn = [tapeId initSCSITape:(int)tapeUnit
  119.         target: stTarget
  120.         lun: stLun
  121.         controller: controllerId
  122.         majorDeviceNumber: major];
  123.  
  124. #ifdef DEBUG
  125. IOLog ("SCSITape probe: irtn is %d\n", irtn);
  126. #endif DEBUG
  127.  
  128.         switch (irtn) {
  129.         case STR_GOOD:
  130.             /*
  131.              * Init'd OK - still must register device.
  132.              */
  133.             [tapeId registerDevice];
  134.             stIdMap [tapeUnit] = tapeId;
  135.             tapeId = nil;
  136.             tapeUnit++;
  137.             if (tapeUnit >= NST) goto done;
  138.             brtn = YES;
  139.             break;
  140.                 
  141.         default:
  142.             [controllerId releaseTarget: stTarget
  143.             lun: stLun
  144.             forOwner: tapeId];
  145.             [tapeId setReservedTargetLun: NO];
  146.             if(irtn == STR_SELECTTO) {
  147.             /*
  148.              * Skip the rest of the luns on 
  149.              * this target.
  150.              */
  151.             goto nextTarget;
  152.             }
  153.         /* 
  154.          * else try next lun.
  155.          */
  156.         }    /* switch (irtn) */
  157.     }    /* for lun */
  158.  
  159. nextTarget:
  160.  
  161.     continue;
  162.     }        /* for target */
  163.     
  164. done:
  165.     /*
  166.      * Free up leftover owner and id.  At this point, tapeId does NOT have
  167.      * a target/lun reserved.
  168.      */
  169.     if(tapeId) {
  170.     [tapeId free];
  171.     }
  172.     
  173.     return brtn;
  174. }
  175.  
  176.  
  177. - (stInitReturn_t) initSCSITape:(int)iunit     /* IODevice unit # */
  178.     target:        (u_char) stTarget
  179.     lun:        (u_char) stLun
  180.     controller:        controllerId
  181.     majorDeviceNumber:    (int) major
  182. {
  183.     inquiry_reply_t    inquiryData;
  184.     sc_status_t        rtn;
  185.     char        driveType[DRIVE_TYPE_LENGTH];    /* name from Inquiry */
  186.     char        *outp;
  187.     char        deviceName[30];
  188.     char        location[IO_STRING_LENGTH];
  189.     
  190.     
  191.     /*
  192.      * Initialize common instance variables.
  193.      */
  194.     _controller = controllerId;
  195.     _target = stTarget;
  196.     _lun = stLun;
  197.     sprintf(deviceName, "st%d", iunit);
  198.     [self setName: deviceName];
  199.     [self setDeviceKind:"SCSITape"];
  200.     [self setLocation:[_controller name]];
  201.     [self setUnit: iunit];
  202.  
  203. #ifdef DEBUG
  204. IOLog 
  205.     ("InitSCSITape: target %d  lun %d  unit %d  deviceName %s  location %s\n",
  206.     stTarget, stLun, iunit, deviceName, [_controller name]);
  207. #endif DEBUG
  208.  
  209.     /*
  210.      * Resources for commands during initialization.
  211.      */
  212.     _senseDataPtr = IOMalloc (sizeof (struct esense_reply));
  213.     _senseDataValid = NO;
  214.  
  215.     /*
  216.      * Other instance variables
  217.      */
  218.     _didWrite = NO;
  219.     _suppressIllegalLength = NO;
  220.     _isInitialized = NO;
  221.     _devLock = nil;            // Until we know we're a tape
  222.  
  223.     /*
  224.      * Test Unit Ready to clear possible Unit Attention.   Success is
  225.      * not important.
  226.      */
  227.     [self stTestReady];
  228.  
  229.     /*
  230.      * Try an Inquiry command.
  231.      */
  232.     bzero(&inquiryData, sizeof(inquiry_reply_t));
  233.     rtn = [self stInquiry:&inquiryData];
  234.  
  235. #ifdef DEBUG
  236. IOLog ("InitSCSITape inquiry returned %d\n", rtn);
  237. #endif DEBUG
  238.  
  239.     switch(rtn) {
  240.     case SR_IOST_GOOD:
  241.         break;
  242.     case SR_IOST_SELTO:
  243.         return STR_SELECTTO;
  244.     default:
  245.         return STR_ERROR;
  246.     }
  247.  
  248.     /*
  249.      * Is it a tape?  
  250.      */
  251.     if(inquiryData.ir_qual != DEVQUAL_OK ||
  252.     inquiryData.ir_devicetype != DEVTYPE_TAPE) {
  253.  
  254. #ifdef DEBUG
  255. IOLog ("InitSCSITape: not a tape\n");
  256. #endif DEBUG
  257.  
  258.     return(STR_NOTATAPE);
  259.     }
  260.     
  261.     /*
  262.      * Set up resources for exclusive open.
  263.      */
  264.     _devLock = [[NXLock alloc] init];
  265.     _devAcquired = NO;
  266.  
  267.     /*
  268.      * Compress multiple blanks out of the vendor id and product ID. 
  269.      */
  270.     bzero (driveType, DRIVE_TYPE_LENGTH);
  271.     outp = driveType;
  272.     outp += moveString((char *)&inquiryData.ir_vendorid,
  273.     outp, 
  274.     8,
  275.     &driveType[DRIVE_TYPE_LENGTH] - outp);
  276.     if(*(outp - 1) != ' ')
  277.     *outp++ = ' ';
  278.     outp += moveString((char *)&inquiryData.ir_productid,
  279.     outp, 
  280.     16,
  281.     &driveType[DRIVE_TYPE_LENGTH] - outp);
  282.     if(*(outp - 1) != ' ')
  283.     *outp++ = ' ';
  284.     outp += moveString((char *)&inquiryData.ir_revision,
  285.     outp, 
  286.     4,
  287.     &driveType[DRIVE_TYPE_LENGTH] - outp);
  288.     *outp = '\0';
  289.  
  290.     sprintf(location, "Target %d LUN %d at %s", _target, _lun,
  291.     [controllerId name]);
  292.     [self setLocation: location];
  293.     IOLog("%s: %s\n", deviceName, driveType);
  294.  
  295.  
  296.     /*
  297.      * Do another Test Unit Ready to clear a possible Unit Attention
  298.      * condition.  We don't care about the result.
  299.      */
  300.     [self stTestReady];
  301.  
  302.     /*
  303.      * Init to variable blk size.
  304.      */
  305.     [self setBlockSize: 0];
  306.  
  307.     /*
  308.      * Store the major number in our instance.
  309.      */
  310.     _majorDevNum = major;
  311.  
  312.     [super init];
  313.     _isInitialized = YES;
  314.     return(STR_GOOD);
  315. } /* - initSCSITape: */
  316.  
  317.  
  318. - free
  319. {
  320.     if (_senseDataPtr)
  321.     IOFree (_senseDataPtr, sizeof (struct esense_reply));
  322.     if (_devLock)
  323.     [_devLock free];
  324.     if (_reservedTargetLun)
  325.     [_controller releaseTarget: _target lun: _lun forOwner: _controller];
  326.     return [super free];
  327. }
  328.  
  329.  
  330. - (IOReturn) getIntValues: (unsigned int *)values
  331.     forParameter: (IOParameterName) parameter
  332.     count: (unsigned int *) count
  333. {
  334.     int maxCount = *count;
  335.  
  336.     if(maxCount == 0) {
  337.         maxCount = IO_MAX_PARAMETER_ARRAY_LENGTH;
  338.     }
  339.  
  340.     if(strcmp(parameter, "IOMajorDevice") == 0) {
  341.     values [0] = [self majorDevNum];
  342.     *count = 1;       
  343.     return IO_R_SUCCESS;
  344.     }
  345.  
  346.     if (strcmp(parameter, "Unit") == 0) {
  347.     values [0] = [self unit];
  348.     *count = 1;       
  349.         return IO_R_SUCCESS;
  350.  
  351.     }
  352.         
  353.     return [super getIntValues:values 
  354.     forParameter:parameter
  355.     count:&maxCount];
  356. }
  357.  
  358.  
  359.  
  360. /*
  361.  * Gets and sets for instance variables.
  362.  */
  363.  
  364. - (int) target            /* Set only during initialization */
  365. {
  366.     return (int) _target;
  367. }
  368.  
  369. - (int) lun            /* Set only during initialization */
  370. {
  371.     return (int) _lun;
  372. }
  373.  
  374. - controller            /* Set only during initialization */
  375. {
  376.     return _controller;
  377. }
  378.  
  379. - (BOOL) isInitialized        /* Object has been initialized */
  380. {
  381.     return _isInitialized;
  382. }
  383.  
  384. - (BOOL) didWrite        /* Last command was a write */
  385. {
  386.     return _didWrite;
  387. }
  388.  
  389. - (BOOL) isFixedBlock
  390. {
  391.     if (_blockSize) {        /* Zero blocksize means variable block size */
  392.     return YES;
  393.     } else {
  394.     return NO;
  395.     }
  396. }
  397.  
  398. - (BOOL) senseDataValid
  399. {
  400.     return _senseDataValid;
  401. }
  402.  
  403. - forceSenseDataInvalid        /* for MTIOCGET and friends */
  404. {
  405.     _senseDataValid = NO;
  406.     return self;
  407. }
  408.  
  409. - (struct esense_reply *) senseDataPtr
  410. {
  411.     return _senseDataPtr;
  412. }
  413.  
  414. - (int) blockSize        /* Set only via setBlockSize SCSI operation */
  415. {
  416.     return _blockSize;
  417. }
  418.  
  419. - (BOOL) suppressIllegalLength
  420. {
  421.     return _suppressIllegalLength;
  422. }
  423.  
  424. - setSuppressIllegalLength: (BOOL) condition
  425. {
  426.     _suppressIllegalLength = condition;
  427.     return self;
  428. }
  429.  
  430. - (BOOL) ignoreCheckCondition
  431. {
  432.     return _ignoreCheckCondition;
  433. }
  434.  
  435. - setIgnoreCheckCondition: (BOOL) condition
  436. {
  437.     _ignoreCheckCondition = condition;
  438.     return self;
  439. }
  440.  
  441. - (int) majorDevNum
  442. {
  443.     return _majorDevNum;
  444. }
  445.  
  446. - setReservedTargetLun: (BOOL) condition
  447. {
  448.     _reservedTargetLun = condition;
  449.     return self;
  450. }
  451.  
  452. - (BOOL) reservedTargetLun
  453. {
  454.     return _reservedTargetLun;
  455. }
  456.  
  457. - (IOReturn) acquireDevice
  458. {
  459.     IOReturn        ret = IO_R_INVALID;
  460.  
  461.     [_devLock lock];
  462.     if (_devAcquired == YES) {
  463.     ret = IO_R_BUSY;
  464.     } else {
  465.     _devAcquired = YES;
  466.     ret = IO_R_SUCCESS;
  467.     }
  468.     [_devLock unlock];
  469.     return ret;
  470. }
  471.  
  472. - (IOReturn) releaseDevice
  473. {
  474.     [_devLock lock];
  475.     _devAcquired = NO;
  476.     [_devLock unlock];
  477.     return IO_R_SUCCESS;
  478. }
  479.  
  480.  
  481. /*
  482.  * General SCSI commands
  483.  */
  484. - (sc_status_t) stInquiry: (inquiry_reply_t *) inquiryReply
  485. {
  486.     IOSCSIRequest         scsiReq;
  487.     cdb_6_t             *cdbp = &scsiReq.cdb.cdb_c6;
  488.     inquiry_reply_t         *alignedReply;
  489.     void             *freePtr;
  490.     int             freeCnt;
  491.     sc_status_t         rtn;
  492.     IODMAAlignment         dmaAlign;
  493.     
  494.     
  495.     /*
  496.      * Get some well-aligned memory.
  497.      */
  498.     alignedReply = [_controller
  499.     allocateBufferOfLength: sizeof(inquiry_reply_t)
  500.     actualStart:&freePtr
  501.     actualLength:&freeCnt];
  502.     bzero(alignedReply, sizeof(inquiry_reply_t));
  503.     bzero(&scsiReq, sizeof(IOSCSIRequest));
  504.     scsiReq.target = _target;
  505.     scsiReq.lun = _lun;
  506.     scsiReq.read = YES;
  507.     
  508.     /*
  509.      * Get appropriate alignment from controller. 
  510.      */
  511.     [_controller getDMAAlignment:&dmaAlign];
  512.     if(dmaAlign.readLength > 1) {
  513.     scsiReq.maxTransfer = IOAlign(int, sizeof(inquiry_reply_t), 
  514.         dmaAlign.readLength);
  515.     }
  516.     else {
  517.     scsiReq.maxTransfer = sizeof(inquiry_reply_t);
  518.     }
  519.  
  520.     scsiReq.timeoutLength = ST_IOTO_NORM;
  521.     scsiReq.disconnect = 1;
  522.  
  523.     cdbp->c6_opcode = C6OP_INQUIRY;
  524.     cdbp->c6_lun = _lun;
  525.     cdbp->c6_len = sizeof(inquiry_reply_t);
  526.     
  527.     [self executeRequest: &scsiReq
  528.     buffer: alignedReply
  529.     client: IOVmTaskSelf()
  530.     senseBuf: _senseDataPtr];
  531.  
  532.     if(scsiReq.driverStatus == SR_IOST_GOOD) {
  533.     unsigned required = (char *)(&alignedReply->ir_zero3[0]) - 
  534.         (char *)(alignedReply);
  535.     if(scsiReq.bytesTransferred < required) {
  536.         IOLog("%s: bad DMA Transfer count (%d) on Inquiry\n", 
  537.         [self name], scsiReq.bytesTransferred);
  538.         rtn = SR_IOST_HW;
  539.     }
  540.     else {
  541.     /*
  542.      * Copy data back to caller's struct. Zero the 
  543.      * portion of alignedReply which did not get valid
  544.      * data; the last flush out of the DMA pipe could
  545.      * have written trash to it (and our caller
  546.      * expects NULL data).
  547.      */
  548.         unsigned zeroSize;
  549.             
  550.         zeroSize = sizeof(*alignedReply) - scsiReq.bytesTransferred;
  551.         if(zeroSize) {
  552.         bzero((char *)alignedReply + scsiReq.bytesTransferred,
  553.             zeroSize);
  554.         }
  555.         *inquiryReply = *alignedReply;
  556.         rtn = scsiReq.driverStatus;
  557.     }
  558.     }
  559.     else {
  560.     rtn = scsiReq.driverStatus;
  561.     }
  562.  
  563.     IOFree(freePtr, freeCnt);
  564.     return rtn;
  565. } /* - stInquiry: */
  566.  
  567.  
  568.  
  569. - (BOOL) stTestReady
  570. {
  571.     IOSCSIRequest    scsiReq;
  572.     cdb_6_t        *cdbp = &scsiReq.cdb.cdb_c6;
  573.     BOOL        rtn;
  574.     
  575.     bzero(&scsiReq, sizeof(IOSCSIRequest));
  576.     scsiReq.target = _target;
  577.     scsiReq.lun = _lun;
  578.     scsiReq.timeoutLength = ST_IOTO_NORM;
  579.     scsiReq.disconnect = 1;
  580.     
  581.     cdbp->c6_opcode = C6OP_TESTRDY;
  582.     cdbp->c6_lun = _lun;
  583.  
  584.     [self executeRequest: &scsiReq
  585.     buffer: (void *) NULL
  586.     client: IOVmTaskSelf()
  587.     senseBuf: _senseDataPtr];
  588.  
  589.     /*
  590.      * XXX Do we need to distinguish not ready from no tape?
  591.      */
  592.     switch(scsiReq.driverStatus) {
  593.     case SR_IOST_GOOD:
  594.         rtn = YES;
  595.         break;
  596.     default:
  597.         rtn = NO;
  598.         break;        
  599.     }
  600.  
  601.     return rtn;
  602. } /* - stTestReady: */
  603.  
  604.  
  605.  
  606. - (sc_status_t) stCloseFile
  607. {
  608.     IOSCSIRequest         scsiReq;
  609.     cdb_6s_t             *cdbp = &scsiReq.cdb.cdb_c6s;
  610.     
  611.     bzero(&scsiReq, sizeof(IOSCSIRequest));
  612.     scsiReq.target = _target;
  613.     scsiReq.lun = _lun;
  614.     scsiReq.timeoutLength = ST_IOTO_NORM;
  615.     scsiReq.disconnect = 1;
  616.     cdbp->c6s_opcode = C6OP_WRTFM;
  617.     assign_cdb_c6s_len (cdbp, 1);        /* one file mark */
  618.     
  619.     return [self executeRequest: &scsiReq
  620.     buffer: NULL
  621.     client: IOVmTaskSelf()
  622.     senseBuf: _senseDataPtr];
  623. } /* - stCloseFile */
  624.  
  625.  
  626. - (sc_status_t) stRewind
  627. {
  628.     IOSCSIRequest         scsiReq;
  629.     cdb_6s_t             *cdbp = &scsiReq.cdb.cdb_c6s;
  630.     
  631.     bzero(&scsiReq, sizeof(IOSCSIRequest));
  632.     scsiReq.target = _target;
  633.     scsiReq.lun = _lun;
  634.     scsiReq.timeoutLength = ST_IOTO_RWD;
  635.     scsiReq.disconnect = 1;
  636.     cdbp->c6s_opcode = C6OP_REWIND;
  637.     
  638.     return [self executeRequest: &scsiReq
  639.     buffer: NULL
  640.     client: IOVmTaskSelf()
  641.     senseBuf: _senseDataPtr];
  642. } /* - stRewind */
  643.  
  644.  
  645. /*
  646.  * Get sense data. senseBuf does not have to be well aligned.
  647.  */
  648. - (sc_status_t) requestSense: (esense_reply_t *)senseBuf
  649. {
  650.     IOSCSIRequest     scsiReq;
  651.     cdb_6_t         *cdbp = &scsiReq.cdb.cdb_c6;
  652.     esense_reply_t     *alignedBuf;
  653.     void         *freePtr;
  654.     int         freeCnt;
  655.     sc_status_t     rtn;
  656.     IODMAAlignment    dmaAlign;
  657.     
  658.     alignedBuf = [_controller allocateBufferOfLength: sizeof(esense_reply_t)
  659.     actualStart: &freePtr
  660.     actualLength: &freeCnt];
  661.     bzero(&scsiReq, sizeof(IOSCSIRequest));
  662.     [_controller getDMAAlignment:&dmaAlign];
  663.  
  664.     scsiReq.target         = _target;
  665.     scsiReq.lun         = _lun;
  666.     scsiReq.read        = YES;
  667.  
  668.     if(dmaAlign.readLength > 1) {
  669.     scsiReq.maxTransfer = IOAlign(int, sizeof(esense_reply_t), 
  670.         dmaAlign.readLength);
  671.  
  672.     } else {
  673.     scsiReq.maxTransfer = sizeof(esense_reply_t);
  674.     }
  675.  
  676.     scsiReq.timeoutLength = ST_IOTO_NORM;  // XXX Should be ST_IOTO_SENSE??
  677.     scsiReq.disconnect = 0;
  678.     cdbp->c6_opcode = C6OP_REQSENSE;
  679.     cdbp->c6_lun = _lun;
  680.     cdbp->c6_len = sizeof(esense_reply_t);
  681.  
  682.     rtn = [_controller executeRequest:&scsiReq
  683.     buffer:alignedBuf
  684.     client:IOVmTaskSelf()];
  685.     if(rtn == SR_IOST_GOOD) {
  686.     *senseBuf = *alignedBuf;
  687.     _senseDataValid = YES;
  688.     }
  689.     IOFree(freePtr, freeCnt);
  690.     return rtn;
  691. } /* - requestSense: */
  692.  
  693.  
  694.  
  695.  
  696. - (sc_status_t) stModeSelect: (struct modesel_parms *) modeSelectParmsPtr
  697. {
  698.     IOSCSIRequest         scsiReq;
  699.     cdb_6_t             *cdbp = &scsiReq.cdb.cdb_c6;
  700.     int                count = modeSelectParmsPtr->msp_bcount;
  701.     struct mode_sel_data     *alignedBuf;
  702.     void             *freePtr;
  703.     int             freeCnt;
  704.     sc_status_t         rtn;
  705.     IODMAAlignment        dmaAlign;
  706.     
  707.     alignedBuf = [_controller 
  708.     allocateBufferOfLength: count
  709.     actualStart: &freePtr
  710.     actualLength: &freeCnt];
  711.  
  712.  
  713.     bzero(&scsiReq, sizeof(IOSCSIRequest));
  714.  
  715.     scsiReq.target         = _target;
  716.     scsiReq.lun         = _lun;
  717.     scsiReq.read        = NO;
  718.  
  719.     [_controller getDMAAlignment:&dmaAlign];
  720.     if(dmaAlign.readLength > 1) {
  721.     scsiReq.maxTransfer = IOAlign(int, count, 
  722.         dmaAlign.readLength);
  723.  
  724.     } else {
  725.     scsiReq.maxTransfer = count;
  726.     }
  727.  
  728.     scsiReq.timeoutLength = ST_IOTO_NORM;
  729.     scsiReq.disconnect = 1;
  730.     cdbp->c6_opcode = C6OP_MODESELECT;
  731.     cdbp->c6_lun = _lun;
  732.     cdbp->c6_len = count;
  733.  
  734.     bcopy (&modeSelectParmsPtr->msp_data, alignedBuf, count);
  735.  
  736.     rtn = [self executeRequest:&scsiReq
  737.     buffer:alignedBuf
  738.     client:IOVmTaskSelf()
  739.     senseBuf: _senseDataPtr];
  740.  
  741.     IOFree(freePtr, freeCnt);
  742.     return rtn;
  743. } /* - stModeSelect: */
  744.  
  745.  
  746.  
  747.  
  748. - (sc_status_t) stModeSense: (struct modesel_parms *) modeSenseParmsPtr
  749. {
  750.     IOSCSIRequest         scsiReq;
  751.     cdb_6_t             *cdbp = &scsiReq.cdb.cdb_c6;
  752.     int                count = modeSenseParmsPtr->msp_bcount;
  753.     struct mode_sel_data     *alignedBuf;
  754.     void             *freePtr;
  755.     int             freeCnt;
  756.     sc_status_t         rtn;
  757.     IODMAAlignment        dmaAlign;
  758.     
  759.     alignedBuf = [_controller 
  760.     allocateBufferOfLength: count
  761.     actualStart: &freePtr
  762.     actualLength: &freeCnt];
  763.  
  764.  
  765.     bzero(&scsiReq, sizeof(IOSCSIRequest));
  766.  
  767.     scsiReq.target         = _target;
  768.     scsiReq.lun         = _lun;
  769.     scsiReq.read        = YES;
  770.  
  771.     [_controller getDMAAlignment:&dmaAlign];
  772.     if(dmaAlign.readLength > 1) {
  773.     scsiReq.maxTransfer = IOAlign(int, count, 
  774.         dmaAlign.readLength);
  775.  
  776.     } else {
  777.     scsiReq.maxTransfer = count;
  778.     }
  779.  
  780.     scsiReq.timeoutLength = ST_IOTO_NORM;
  781.     scsiReq.disconnect = 1;
  782.     cdbp->c6_opcode = C6OP_MODESENSE;
  783.     cdbp->c6_lun = _lun;
  784.     cdbp->c6_len = count;
  785.  
  786.     rtn = [self executeRequest:&scsiReq
  787.     buffer:alignedBuf
  788.     client:IOVmTaskSelf()
  789.     senseBuf: _senseDataPtr];
  790.  
  791.     if(rtn == SR_IOST_GOOD) {
  792.     bcopy (alignedBuf, &modeSenseParmsPtr->msp_data, count);
  793.     }
  794.  
  795.     IOFree(freePtr, freeCnt);
  796.     return rtn;
  797. } /* - stModeSense: */
  798.  
  799.  
  800.  
  801. - (sc_status_t) executeMTOperation: (struct mtop *) mtopp
  802. {
  803.     IOSCSIRequest         scsiReq;
  804.     cdb_6s_t             *cdbp = &scsiReq.cdb.cdb_c6s;
  805.     int                count;
  806.     sc_status_t            rtn;
  807.     
  808.     bzero(&scsiReq, sizeof(IOSCSIRequest));
  809.     scsiReq.target = _target;
  810.     scsiReq.lun = _lun;
  811.     scsiReq.timeoutLength = ST_IOTO_NORM;    /* Some ops override this */
  812.     scsiReq.disconnect = 1;  // XXX - maybe not for all ops.
  813.  
  814.     /* 
  815.      * none of these operations performs DMA. For each, just fill in
  816.      * the cdb, and pass it to the controller.
  817.      */
  818.      
  819.     /* build a CDB */
  820.     
  821.     switch(mtopp->mt_op) {
  822.     case MTWEOF:        /* write file marks */
  823.         cdbp->c6s_opcode = C6OP_WRTFM;
  824.         goto setcount_f;
  825.         
  826.     case MTFSF:        /* space file marks forward */
  827.         cdbp->c6s_opcode = C6OP_SPACE;
  828.         cdbp->c6s_opt = C6OPT_SPACE_FM;
  829.         scsiReq.timeoutLength = mtopp->mt_count * ST_IOTO_SPFM;
  830.         goto setcount_f;
  831.         
  832.     case MTBSF:        /* space file marks backward */
  833.         cdbp->c6s_opcode = C6OP_SPACE;
  834.         cdbp->c6s_opt = C6OPT_SPACE_FM;
  835.         scsiReq.timeoutLength = mtopp->mt_count * ST_IOTO_SPFM;
  836.         goto setcount_b;
  837.         
  838.     case MTFSR:        /* space records forward */
  839.         cdbp->c6s_opcode = C6OP_SPACE;
  840.         cdbp->c6s_opt = C6OPT_SPACE_LB;
  841.         scsiReq.timeoutLength = ST_IOTO_SPR;
  842. setcount_f:
  843.         assign_cdb_c6s_len (cdbp, mtopp->mt_count);
  844.         break;
  845.  
  846.     case MTBSR:            /* space records backward */
  847.         cdbp->c6s_opcode = C6OP_SPACE;
  848.         cdbp->c6s_opt = C6OPT_SPACE_LB;
  849.         scsiReq.timeoutLength = ST_IOTO_SPR;
  850. setcount_b:
  851.         count = 0 - mtopp->mt_count;
  852.         assign_cdb_c6s_len (cdbp, count);
  853.         break;
  854.             
  855.     case MTREW:            /* rewind */
  856.         cdbp->c6s_opcode = C6OP_REWIND;
  857.         scsiReq.timeoutLength = ST_IOTO_RWD;
  858.         break;
  859.         
  860.     case MTOFFL:            /* set offline */
  861.         cdbp->c6s_opcode = C6OP_STARTSTOP;
  862.                     /* note load bit is 0 */
  863.         scsiReq.timeoutLength = ST_IOTO_RWD;
  864.         break;
  865.         
  866.     case MTNOP:        /* nop / get status */
  867.     case MTCACHE:        /* enable cache */
  868.     case MTNOCACHE:        /* disable cache */
  869.     case MTRETEN:
  870.     case MTERASE:
  871.     default:
  872.         rtn = SR_IOST_CMDREJ;    /* FIXME: unsupported? */
  873.         goto out;
  874.     }
  875.  
  876.     rtn = [self executeRequest: &scsiReq
  877.     buffer: NULL
  878.     client: IOVmTaskSelf()
  879.     senseBuf: _senseDataPtr];   
  880. out:
  881.     return rtn;
  882. } /* - executeMTOperation: */
  883.  
  884.     
  885.  
  886. /*
  887.  * Set block size for SCSI tape device.   
  888.  *
  889.  * blocksize == 0 --> variable
  890.  * blocksize != 0 --> fixed @ blocksize
  891.  *
  892.  * First, execute mode sense, then mode select with block length
  893.  * set to 0 (variable) or blocksize (fixed)
  894.  */
  895. - (IOReturn) setBlockSize: (int) blockSize
  896. {
  897.     int                rtn;
  898.     struct modesel_parms    *mspp;
  899.     struct mode_sel_hdr        *mshp;
  900.  
  901.     mspp = IOMalloc (sizeof(struct modesel_parms));
  902.     mspp->msp_bcount = sizeof(struct mode_sel_hdr) + 
  903.     sizeof(struct mode_sel_bd);
  904.  
  905.     if((rtn = [self stModeSense: mspp]) != SR_IOST_GOOD) {
  906.     IOFree (mspp, sizeof (struct modesel_parms));
  907.     return [_controller returnFromScStatus: rtn];
  908.     }
  909.  
  910.     mshp = &mspp->msp_data.msd_header;    
  911.     mshp->msh_sd_length_0 = 0;
  912.     mshp-> msh_med_type = 0;
  913.     mshp-> msh_wp = 0;
  914.     mshp-> msh_bd_length = sizeof(struct mode_sel_bd);
  915.     assign_msbd_blocklength 
  916.     (&mspp->msp_data.msd_blockdescript, blockSize);
  917.     assign_msbd_numblocks
  918.     (&mspp->msp_data.msd_blockdescript, 0);
  919.  
  920.     if((rtn = [self stModeSelect: mspp]) != SR_IOST_GOOD) {
  921.     IOFree (mspp, sizeof (struct modesel_parms));
  922.     return [_controller returnFromScStatus: rtn];
  923.     }
  924.  
  925.     _blockSize = blockSize;
  926.  
  927.     IOFree (mspp, sizeof (struct modesel_parms));
  928.     return IO_R_SUCCESS;
  929. } /* - setBlockSize: */
  930.  
  931.  
  932.  
  933.  
  934. /*
  935.  * Execute CDB.   Buffer must be well aligned.   If command results 
  936.  * in Check Status, return the sense data in *senseBuf.
  937.  */
  938. - (sc_status_t) executeRequest: (IOSCSIRequest *)scsiReq
  939.     buffer:(void *) buffer /* data destination */
  940.     client:(vm_task_t) client
  941.     senseBuf:(esense_reply_t *) senseBuf
  942. {
  943.     sc_status_t            rtn;
  944.  
  945.     _senseDataValid = NO;
  946.  
  947. #ifdef DEBUG
  948. IOLog("Entered SCSI Tape executeRequest: op %s, maxTransfer %d, len %d\n",
  949.     IOFindNameForValue(scsiReq->cdb.cdb_opcode,
  950.     IOSCSIOpcodeStrings),
  951.     scsiReq->maxTransfer,
  952.     (scsiReq->cdb.cdb_c6s.c6s_len2 << 16) | 
  953.     (scsiReq->cdb.cdb_c6s.c6s_len1 << 8) |
  954.     (scsiReq->cdb.cdb_c6s.c6s_len0));
  955. #endif DEBUG
  956.  
  957.     rtn = [_controller executeRequest:scsiReq
  958.     buffer:buffer
  959.     client:client];
  960.  
  961. #ifdef DEBUG
  962. IOLog ("Length %d on return from executeRequest\n", scsiReq->bytesTransferred);
  963. #endif DEBUG
  964.  
  965.     /*
  966.      * Log error returns.
  967.      */
  968.     if (rtn != SR_IOST_GOOD) {
  969.     /*
  970.      * If result is Check Condition, do a Request Sense, unless suppressed.
  971.      */
  972.     if(rtn == SR_IOST_CHKSV) {
  973.         /* 
  974.          * Host Adaptor already got us sense data. Give sense data
  975.          * to user and save it.
  976.          */
  977.         *senseBuf = *_senseDataPtr = scsiReq->senseData;
  978.         _senseDataValid = YES;
  979.     }
  980.     if (((rtn == SR_IOST_CHKSNV) || (rtn == SR_IOST_CHKSV)) &&
  981.            !_ignoreCheckCondition) {
  982.         if(rtn == SR_IOST_CHKSV) {
  983.             rtn = SR_IOST_GOOD;
  984.         }
  985.         else {
  986.         rtn = [self requestSense: senseBuf];
  987.         }
  988.         if(rtn == SR_IOST_GOOD) {
  989.         /*
  990.          * If the error is a filemark, and we are reading,
  991.          * then return no error.   Otherwise, return
  992.          * check sense, with valid sense data.
  993.          */
  994.         if ((scsiReq->cdb.cdb_c6.c6_opcode == C6OP_READ) &&
  995.             (senseBuf->er_filemark)) {
  996.  
  997.             /*
  998.              * Check for correct reporting of bytes transferred.
  999.              * (This works around a DPT firmware bug.)
  1000.              */
  1001.             int    transferLength = 
  1002.             cdb_c6s_len_value (&scsiReq->cdb.cdb_c6s) -
  1003.             er_info_value (senseBuf);
  1004.  
  1005.             if ([self isFixedBlock]) {
  1006.             transferLength = transferLength * _blockSize;
  1007.             }
  1008.                     
  1009.             if (scsiReq->bytesTransferred != transferLength) {
  1010. #ifdef DEBUG
  1011. IOLog ("%s: Incorrect byte count reported - "
  1012.     "corrected to %d\n", [self name], transferLength);
  1013. #endif DEBUG
  1014.             scsiReq->bytesTransferred = transferLength;
  1015.             }
  1016.  
  1017.             rtn = SR_IOST_GOOD;
  1018.             scsiReq->driverStatus = SR_IOST_GOOD;
  1019.  
  1020. #ifdef DEBUG
  1021. IOLog ("execReq sense: er_filemark %d, er_badlen %d, er_sensekey %d, er_addsensecode %d, er_qualifier %d, er_info %d\n", 
  1022.     senseBuf->er_filemark, senseBuf->er_badlen, senseBuf->er_sensekey,
  1023.     senseBuf->er_addsensecode, senseBuf->er_qualifier,
  1024.     er_info_value (senseBuf));
  1025. #endif DEBUG
  1026.  
  1027.         }
  1028.         else {
  1029.             rtn = SR_IOST_CHKSV;
  1030.         }
  1031.         }
  1032.         else {
  1033.          if (_isInitialized) {
  1034.             IOLog("%s: Request Sense on target %d lun %d "
  1035.             "failed (%s)\n",
  1036.             [self name], _target, _lun, 
  1037.             IOFindNameForValue(rtn, IOScStatusStrings));
  1038.         }
  1039.         rtn = SR_IOST_CHKSNV;
  1040.         }
  1041.     }
  1042.  
  1043.     /*
  1044.      * Log error messages, except the spate of timeouts and
  1045.      * device not ready messages during initialization.
  1046.      */
  1047.     if (_isInitialized &&
  1048.         (rtn != SR_IOST_GOOD) &&
  1049.         !_ignoreCheckCondition) {
  1050.  
  1051.         IOLog("%s, target %d, lun %d: op %s returned %s\n",
  1052.         [self name], _target, _lun,
  1053.         IOFindNameForValue(scsiReq->cdb.cdb_opcode,
  1054.             IOSCSIOpcodeStrings),
  1055.         IOFindNameForValue(rtn, IOScStatusStrings));
  1056.  
  1057.         if (rtn == SR_IOST_CHKSV) {
  1058.         IOLog ("    Sense key = 0x%x  Sense Code = 0x%x\n",
  1059.             senseBuf->er_sensekey, senseBuf->er_addsensecode);
  1060.         }
  1061.     }
  1062.  
  1063.     _didWrite = NO;
  1064.     }
  1065.  
  1066.     else {
  1067.     /* Remember good writes for device close */
  1068.     if (scsiReq->cdb.cdb_opcode == C6OP_WRITE) {
  1069.         _didWrite = YES;
  1070.     } else {
  1071.         _didWrite = NO;
  1072.     }
  1073.     }
  1074.  
  1075.     return rtn;
  1076. } /* executeRequest: */               
  1077.               
  1078. @end
  1079.  
  1080. /*
  1081.  * Supporting functions.
  1082.  */
  1083.  
  1084. /*
  1085.  * moveString is taken directly from SCSIDiskPrivate.m.    
  1086.  * It's used by -initSCSITape:
  1087.  *
  1088.  * Copy inp to outp for up to inlength input characters or outlength output
  1089.  * characters. Compress multiple spaces and eliminate nulls. Returns number
  1090.  * of characters copied to outp.
  1091.  */
  1092. static int 
  1093. moveString(char *inp, char *outp, int inlength, int outlength)
  1094. {
  1095.     int lastCharSpace = 0;
  1096.     char *outpStart = outp;
  1097.  
  1098.     while(inlength && outlength) {
  1099.     switch(*inp) {
  1100.         case '\0':
  1101.         inp++;
  1102.         inlength--;
  1103.         continue;
  1104.         case ' ':
  1105.         if(lastCharSpace) {
  1106.             inp++;
  1107.             inlength--;
  1108.             continue;
  1109.         }
  1110.         lastCharSpace = 1;
  1111.         goto copyit;
  1112.         default:
  1113.         lastCharSpace = 0;
  1114. copyit:
  1115.         *outp++ = *inp++;
  1116.         inlength--;
  1117.         outlength--;
  1118.         break;
  1119.         }
  1120.     }
  1121.     return(outp - outpStart);
  1122. }
  1123.  
  1124.  
  1125.  
  1126. void
  1127. assign_cdb_c6s_len (struct cdb_6s *cdbp, int length)
  1128. {
  1129. #if    __BIG_ENDIAN__
  1130. #if    __NATURAL_ALIGNMENT__
  1131.     cdbp->c6s_len[0] = (length >> 16) & 0xff;
  1132.     cdbp->c6s_len[1] = (length >> 8) & 0xff;
  1133.     cdbp->c6s_len[2] = length & 0xff;
  1134.  
  1135. #else    __NATURAL_ALIGNMENT__
  1136.  
  1137.     cdbp->c6s_len = length;
  1138.  
  1139. #endif    __NATURAL_ALIGNMENT__
  1140.  
  1141.  
  1142. #elif    __LITTLE_ENDIAN__
  1143.  
  1144.     cdbp->c6s_len0 = (u_char) length & 0xff;
  1145.     cdbp->c6s_len1 = (u_char) (length >> 8) & 0xff;
  1146.     cdbp->c6s_len2 = (u_char) (length >> 16) & 0xff;
  1147.  
  1148. #endif
  1149.  
  1150.     return;
  1151. }
  1152.  
  1153. void
  1154. assign_msbd_numblocks (struct mode_sel_bd *msbdp, int numblocks)
  1155. {
  1156. #if    __BIG_ENDIAN__
  1157.     msbdp->msbd_numblocks = numblocks;
  1158. #elif    __LITTLE_ENDIAN__
  1159.     msbdp->msbd_numblocks0 = (u_char) numblocks & 0xff;
  1160.     msbdp->msbd_numblocks1 = (u_char) (numblocks >> 8) & 0xff;
  1161.     msbdp->msbd_numblocks2 = (u_char) (numblocks >> 16) & 0xff;
  1162. #endif
  1163.     return;
  1164. }
  1165.  
  1166. void
  1167. assign_msbd_blocklength (struct mode_sel_bd *msbdp, int length)
  1168. {
  1169. #if    __BIG_ENDIAN__
  1170.     msbdp->msbd_blocklength = length;
  1171. #elif    __LITTLE_ENDIAN__
  1172.     msbdp->msbd_blocklength0 = (u_char) length & 0xff;
  1173.     msbdp->msbd_blocklength1 = (u_char) (length >> 8) & 0xff;
  1174.     msbdp->msbd_blocklength2 = (u_char) (length >> 16) & 0xff;
  1175. #endif
  1176.     return;
  1177. }
  1178.  
  1179. int
  1180. cdb_c6s_len_value (struct cdb_6s *cdbp)
  1181. {
  1182. #if    __BIG_ENDIAN__
  1183.     return (cdbp->c6s_len);
  1184. #elif    __LITTLE_ENDIAN__
  1185.     return (cdbp->c6s_len0 | (cdbp->c6s_len1 << 8) | (cdbp->c6s_len2 << 16));
  1186. #endif
  1187. }
  1188.  
  1189. int
  1190. er_info_value (struct esense_reply *esrp)
  1191. {
  1192. #if    __BIG_ENDIAN__
  1193.     return (esrp->er_info);
  1194. #elif    __LITTLE_ENDIAN__
  1195.     return (esrp->er_info0 | (esrp->er_info1 << 8) |
  1196.     (esrp->er_info2 << 16) | (esrp->er_info3 << 24));
  1197. #endif
  1198. }
  1199.     
  1200.